# -*- coding: utf-8 -*-#

# -------------------------------------------------------------------------------
# Name:         base
# Description:  策略基础函数
# Author:       ylf
# Date:         7/14/21
# -------------------------------------------------------------------------------


import numpy as np
import pandas as pd


def conform_signal(data):
    """
    整合信号
    :return:
    """
    # 根据时间生成交易信号
    # 周一买
    # index的设置有点问题，无法读取到

    # 排除交易信号的异常情况(目前的情况比较单一，还没有完全解决)
    # 2  剔除掉第二次出现的交易信号【就是连续出现两次1或者两次-1的情况】
    data['buy_signal'] = np.where((data['buy_signal'] == 1) & (
        data['buy_signal'].shift(1) == 1), 0, data['buy_signal'])
    data['sell_signal'] = np.where(
        (data['sell_signal'] == -
         1) & (
            data['sell_signal'].shift(1) == -
            1),
        0,
        data['sell_signal'])
    data['singal'] = data['buy_signal'] + data['sell_signal']
    # 生成合并后正常的交易信号
    return data


def fix_signal(data):
    """
    修正信号
    :param data:dataframe
    :return: 修正信号
    """
    return data[data['singal'] != 0]


def calculate_return_rate(data):
    """
    计算单次收益率
    :param data:
    :return:
    """
    # 计算每一次开仓平仓后的收益率情况
    # 此处要特别注意解决copywarinng的问题
    # .loc的意思是，首先读取不为0部分，然后设置per_income，将读写合一，就不会出现copy的问题
    data.loc[data['singal'] != 0, 'per_income'] = (
        data['close'] - data['close'].shift(1)) / data['close'].shift(1)
    data = data[data['singal'] == -1]
    return data


def calculate_sum_rate(data):
    """
    计算总收益率  （1+单次收益率）*（1+单次收益率）(依次类推)****-1
    :param data:
    :return: data
    """
    # 特别注意次数的累计的方法
    # 1 将数据转换为dataframe
    # 2 利用dataframe方法的cumpord方法
    data['sum_rate'] = pd.DataFrame((1 + data['per_income'])).cumprod() - 1
    return data


def caculate_combination_rate(data, signals, n):
    """
    计算组合收益率
    :param data:dataframe
    :param signals: 信号
    :param n: 计算数据
    :return: 收益率
    """
    # 1 根据买卖信号确定当前周期内的持仓股票
    print(data.shift(-1))
    # 2 进行数据的求和操作
    returns = (signals * data.shift(-1)).T.sum() / n
    return returns


def calculate_max_drawdown(data):
    """
    计算最大回撤
    :param data:
    :return:
    """
    # 1 选取时间窗口
    window = 3
    # 2 获取时间窗口内的最大值
    # rolling 代表当前时间往前推3个窗口，获取的最大值
    data['rolling_max'] = data['close'].rolling(
        window=window, min_periods=1).max()
    # 3 计算当天的最大回撤，并加入数据集[公式：当天close/最大值-1]
    data['max_dd_daily'] = data['close'] / data['rolling_max'] - 1
    # 4 获取当天最大回撤中的最大值，并加入数据集，往前推3个时间窗口，取得的最小值
    data['max_dd'] = data['max_dd_daily'].rolling(
        window=window, min_periods=1).min()
    return data


def calculate_sharpe_rate(data):
    """
    计算夏普比率
    夏普比率计算公式：（回报率的均值-无风险利率）/回报率标准差
    收益率：（今天的收盘价-昨天的收盘价）/昨天收盘价
    无风险利率：默认为0
    回报率标准差： std()
    :param data:
    :return:
    """
    # daily_return = (data['close']-data['close'].shift())/data['close'].shift()
    # print(data)
    daily_return = data['close'].pct_change()  # 计算收益率，等同于上面的公式
    avg_return = daily_return.mean()  # 计算收益率均值
    sd_return = daily_return.std()  # 利用df自带的std进行标准差的计算

    # 计算夏普比率
    sharp = avg_return / sd_return
    # 计算夏普年利率
    sharp_year = sharp * np.sqrt(252)
    return sharp, sharp_year
